#ifndef __C_TRAPS_BASIC_H__
#define __C_TRAPS_BASIC_H__

#include "std/list.h"
#include "arch/cpu.h"
#include "kernel/spinlock.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifndef KERNEL_CS
#define KERNEL_CS		(0x08)
#endif

// predefined device id
#define DEVID_TIMER			(100)
#define DEVID_KEYBOARD		(101)
#define DEVID_MOUSE			(102)
#define DEVID_ATA_MASTER	(103)
#define DEVID_ATA_SLAVE		(104)

// status: reason for being disabled
#define IRQ_INPROGRESS		(1)
#define IRQ_DISABLED		(2)
#define IRQ_PENDING			(4)
#define IRQ_WAITING			(8)

extern uint irq_err_count;

struct idt_node
{
	unsigned int low;
	unsigned int high;
} PACKED;

typedef struct idt_node idt_node_t;
typedef struct idt_node gate_node_t;

extern idt_node_t idt_table[256];

struct regs
{
	uint	ebx;			// 0
	uint	ecx;			// 4
	uint	edx;			// 8
	uint	esi;			// 12
	uint	edi;			// 16
	uint	ebp;			// 20
	uint	gs;				// 24
	uint	fs;				// 28
	uint	ds;				// 32
	uint	es;				// 36
	uint	eax;			// 40
	union {
		uint	error_code;
		uint	irq;
	} u;					// 44
	uint	eip;			// 48
	uint	cs;				// 52
	uint	eflags;			// 56
	uint	esp;			// 60
	uint	ss;				// 64
} PACKED;

typedef struct regs regs_t;
typedef struct regs pt_regs;

typedef struct irq_cpustat
{
	uint softirq_active;
	uint softirq_mask;
	uint local_irq_count;
	uint local_tasklet_count;
	uint syscall_count;
}
irq_cpu_stat_t;

extern irq_cpu_stat_t irq_stat[NR_CPUS];

#define in_interrupt()			(irq_stat[smp_processor_id()].local_irq_count	\
	+ irq_stat[smp_processor_id()].local_tasklet_count != 0)

#define softirq_active(cpu)		(irq_stat[cpu].softirq_active)
#define softirq_mask(cpu)		(irq_stat[cpu].softirq_mask)
#define irq_enter(cpu, irq)		irq_stat[cpu].local_irq_count++
#define irq_exit(cpu, irq)		irq_stat[cpu].local_irq_count--
#define local_tasklet_disable()	(irq_stat[smp_processor_id()].local_tasklet_count++)
#define local_tasklet_enable()	(irq_stat[smp_processor_id()].local_tasklet_count--)

// faults
#define PAGE_NOT_PRESENT(e)			(((e) & 1) == 0)
#define PAGE_PROTECTION_FAULT(e)	((e) & 1)
#define PAGE_ERR_IN_READ_(e)		(((e) & 2) == 0)
#define PAGE_ERR_IN_WRITE(e)		((e) & 2)
#define PAGE_ERROR_KERNEL(e)		(((e) & 4) == 0)
#define PAGE_ERROR_USER(e)			((e) & 4)

// extern functions
extern void default_intr_hdr(void);
extern void divide_error_trap_hdr(void);
extern void invalid_instruction_trap_hdr(void);
extern void gpf_trap_hdr(void);
extern void page_fault_trap_hdr(void);

// i8259 initialization
void init_8259A(void);

// global init function
void i386_init_traps(void);

// trap handler (divide by 0)
void handle_divide_error(regs_t regs);

// trap handler (page fault)
void handle_page_fault(regs_t regs);
 
#ifdef __cplusplus
}
#endif
#endif
/* EOF */
